package FCRendering.azer;

import FCRendering.FCRBattleOrderConstant;
import FCRendering.FCRMaster;
import Function.FCMapLibrary;
import Function.FCMutilPlayCache;
import Function.FCMutilPlayTankCache;
import VWorldGameStudio.*;
import VWorldGameStudio.events.DoorEvent;
import VWorldGameStudio.events.JumpEvent;
import socket.FCRSocketClient;
import socket.FCRSocketServer;
import utils.FCMixUtil;

import java.util.ArrayList;
import java.util.function.BiConsumer;

import static FCRendering.FCRMaster.*;

/**
 * @Description 玩家动作管理类，负责处理玩家的各种操作逻辑，包括移动、状态更新等。
 * @Author JingTingFeng
 * @Create 2021-05-30 12:04
 */
public class PlayerAction {
    // 系数
    public boolean changeHostId = false; // 是否需要更改主机ID
    private static final PlayerAction instance = new PlayerAction(); // 单例实例
    private int stepRecord = 0; // 记录步数

    private PlayerAction() {
        // 私有构造函数，防止外部实例化
    }

    public static PlayerAction getInstance() {
        return instance; // 获取单例实例
    }

    /**
     * 执行玩家动作，并判断是否需要同步状态。
     * 
     * @return 如果有偏移量或坐标发生变化，则返回 true，表示需要同步状态；否则返回 false。
     */
    public boolean playerAction() {
        int vSpeedLevel = 6; // 设置速度等级
        int vPerStep = (int) (64 * fcv.getProportion() / vSpeedLevel); // 每步走的像素数
        return moveAction(vPerStep, player1.getActionDir()); // 调用移动方法并返回结果
    }

    /**
     * 检查并更新长期状态（如毒气、酸腐蚀等），并在必要时同步血量变化。
     */
    public void stepChangeAndCheckLongTermState() {
        if (gameSave.getQiXiPingBiSteps() > 0) { // 检查气息屏蔽器步骤
            gameSave.setQiXiPingBiSteps(gameSave.getQiXiPingBiSteps() - 1); // 减少一步
            if (gameSave.getQiXiPingBiSteps() == 0) { // 如果步骤为0
                gameSave.setYuGuaiJilv(80); // 重置遇敌几率
                fcv.getMessage().add("气息屏蔽已经失效"); // 添加消息
                fcv.showMessage(); // 显示消息
            }
        }

        if (stepRecord == 0) { // 初始化步数记录
            stepRecord = gameSave.getStepCount();
        } else if (gameSave.getStepCount() - stepRecord > 2) { // 每两步检查一次
            FCLongTermState state = player1.getLongTermMap().get(FCRBattleOrderConstant.S_Acid); // 获取酸状态
            ArrayList<FCPlayerInfo> needSyncRemoteBlood = new ArrayList<>(0); // 需要同步血量的玩家列表
            FCTank drvTank = tankLib.getTankOfID(player1.getPlayertank1(), player1.getPlayertankHostId()); // 获取当前驾驶的坦克
            if (state != null) { // 如果存在酸状态
                int val = state.value; // 获取酸值
                player1.subBlood(Math.max(5, (int) (val * (1f - (float) player1.getPlayerAcidDefend() / 100)))); // 扣除血量
                needSyncRemoteBlood.add(player1); // 添加到同步列表
            }
            state = player1.getLongTermMap().get(FCRBattleOrderConstant.S_Gas); // 获取中毒状态
            if (state != null) { // 如果存在中毒状态
                int val = state.value; // 获取中毒值
                if (drvTank != null && (drvTank.isOpenKongTiao() || drvTank.isOpenQiShan())) { // 如果坦克开启空调或气扇
                    val = (int) (val * 0.6); // 减少中毒效果
                }
                player1.subBlood(Math.max(5, (int) (val * (1f - (float) player1.getPlayerGasDefend() / 100)))); // 扣除血量
                if (!needSyncRemoteBlood.contains(player1)) { // 如果不在同步列表中
                    needSyncRemoteBlood.add(player1); // 添加到同步列表
                }
            }
            if (player1.isDeath()) { // 如果玩家死亡
                gameSave.useTankOfPlayerId(player1, player1.getPlayertank1(), player1.getPlayertankHostId()); // 下车
            }

            FCMixUtil.mayBeGetReduice(tankLib.getTankOfID(player1.getPlayertank1(), player1.getPlayertankHostId())); // 随机获得鸟粪

            for (FCRPlayerLink fcrPlayerLink : FCMutilPlayCache.getTeamMembers()) { // 遍历团队成员
                if (fcrPlayerLink.curPlayerHostUID.equals(gameSave.HOST_UID)) { // 如果是当前主机玩家
                    FCPlayerInfo p = FCMutilPlayCache.findPlayerByName(fcrPlayerLink.curPlayerHostUID, fcrPlayerLink.curPlayerName); // 查找玩家信息
                    if (p != null) { // 如果找到玩家
                        int val = 0; // 初始化值
                        drvTank = tankLib.getTankOfID(p.getPlayertank1(), p.getPlayertankHostId()); // 获取玩家驾驶的坦克
                        state = p.getLongTermMap().get(FCRBattleOrderConstant.S_Acid); // 获取酸状态
                        if (state != null) { // 如果存在酸状态
                            val = state.value; // 获取酸值
                            p.subBlood(Math.max(5, (int) (val * (1f - (float) player1.getPlayerAcidDefend() / 100)))); // 扣除血量
                            needSyncRemoteBlood.add(p); // 添加到同步列表
                        }
                        state = p.getLongTermMap().get(FCRBattleOrderConstant.S_Gas); // 获取中毒状态
                        if (state != null) { // 如果存在中毒状态
                            val = state.value; // 获取中毒值
                            if (drvTank != null && (drvTank.isOpenKongTiao() || drvTank.isOpenQiShan())) { // 如果坦克开启空调或气扇
                                val = (int) (val * 0.6); // 减少中毒效果
                            }
                            p.subBlood(Math.max(5, (int) (val * (1f - (float) player1.getPlayerGasDefend() / 100)))); // 扣除血量
                            if (!needSyncRemoteBlood.contains(p)) { // 如果不在同步列表中
                                needSyncRemoteBlood.add(p); // 添加到同步列表
                            }
                        }
                        if (p.isDeath()) { // 如果玩家死亡
                            gameSave.useTankOfPlayerId(p, p.getPlayertank1(), p.getPlayertankHostId()); // 下车
                        }

                        FCMixUtil.mayBeGetReduice(tankLib.getTankOfID(p.getPlayertank1(), p.getPlayertankHostId())); // 随机获得鸟粪
                    }
                }
            }
            stepRecord = gameSave.getStepCount(); // 更新步数记录
            if (FCRMaster.fcv.isSever()) { // 如果是服务器
                FCRSocketServer.getIn().syncPlayerState(needSyncRemoteBlood); // 同步玩家状态
            } else if (FCRMaster.fcv.isClient()) { // 如果是客户端
                FCRSocketClient.getIn().syncPlayerState(needSyncRemoteBlood); // 同步玩家状态
            }

            gameSave.getTankSaveIos().forEach(new BiConsumer<String, FCTank>() { // 遍历所有战车
                @Override
                public void accept(String s, FCTank tank) {
                    FCMixUtil.stepCheckAcidAndSubDefense(tank); // 检查酸和防御
                }
            });

            if (!fcv.isInTeamLink()) { // 如果不在团队链接中
                if (player1.isDeath()) { // 如果玩家死亡
                    fcv.setPlayingEvent(eventLib.getEventOfName("WelcomeToMingQi")); // 设置播放事件
                    fcv.setJumpactionnum(0); // 设置跳跃动作编号
                    JumpEvent jumpEvent = (JumpEvent) fcv.getPlayingEvent(); // 获取跳跃事件
                    sound.setEffectSound(jumpEvent.getMusicnum0()); // 设置音效
                    if (FCRMaster.fcv.isSever()) { // 如果是服务器
                        FCRSocketServer.getIn().playerJumpEvent(fcv.getPlayingEvent().getName(), jumpEvent.getDestination()); // 通知队友转场
                    } else if (FCRMaster.fcv.isClient()) { // 如果是客户端
                        FCRSocketClient.getIn().playerJumpEvent(fcv.getPlayingEvent().getName(), jumpEvent.getDestination()); // 通知队友转场
                    }

                    FCRMaster.fcrMaster.startToSeeMingQi(); // 开始见明奇
                }
            }
        }
    }

    /**
     * 移动玩家角色，并根据方向调整偏移量。
     * 
     * @param vPerStep 每步的像素偏移量。
     * @param playerDir 玩家移动的方向（上、下、左、右）。
     * @return 如果有偏移量或坐标发生变化，则返回 true；否则返回 false。
     */
    public boolean moveAction(int vPerStep, int playerDir){
        if (changeHostId) { // 如果需要更改主机ID
            return false; // 返回false
        }
        FCPlayerInfo player1 = FCRMaster.player1; // 获取玩家信息
        FCSave gamesave = FCRMaster.gameSave; // 获取游戏保存信息
        FCMapLibrary mapl = FCRMaster.mapLib; // 获取地图库
        int offsetX = FCRMaster.player1.getPianYiX(); // 获取X轴偏移量
        int offsetY = FCRMaster.player1.getPianYiY(); // 获取Y轴偏移量
        int playerX = FCRMaster.player1.getPlayer1x(); // 获取玩家X坐标
        int playerY = FCRMaster.player1.getPlayer1y(); // 获取玩家Y坐标

        int up = 3; // 上方方向
        int right = 2; // 右方方向
        int down = 0; // 下方方向
        int left = 1; // 左方方向

        boolean hasDriverTankInTeam = false; // 是否有驾驶坦克的队友
        boolean canTankGo = true; // 坦克是否可以移动
        boolean allDie = true; // 是否所有人都死亡
        if (!player1.getPlayertank1().equals("null")) { // 如果玩家驾驶了坦克
            hasDriverTankInTeam = true; // 设置有驾驶坦克的队友
            FCTank tank = tankLib.getTankOfID(player1.getPlayertank1(), player1.getPlayertankHostId()); // 获取坦克
            if (tank != null && !tank.canMove()) { // 如果坦克不能移动
                canTankGo = false; // 设置坦克不能移动
            }
        }
        if (!player1.isDeath()) allDie = false; // 如果玩家未死亡，设置所有人未死亡

        if (canTankGo) { // 如果坦克可以移动
            for (FCRPlayerLink fcrPlayerLink : FCMutilPlayCache.getTeamMembers()) { // 遍历团队成员
                if (fcrPlayerLink.curPlayerHostUID.equals("npc") || fcrPlayerLink.curPlayerHostUID.equals(gamesave.HOST_UID)) { // 如果是NPC或当前主机玩家
                    FCPlayerInfo p = FCMutilPlayCache.findPlayerByName(fcrPlayerLink.curPlayerHostUID, fcrPlayerLink.curPlayerName); // 查找玩家信息
                    if (p == null) continue; // 如果找不到玩家，跳过
                    if (!p.isDeath()) { // 如果玩家未死亡
                        allDie = false; // 设置所有人未死亡
                    }
                    if (!p.getPlayertank1().equals("null")) { // 如果玩家驾驶了坦克
                        hasDriverTankInTeam = true; // 设置有驾驶坦克的队友
                        FCTank tank = tankLib.getTankOfID(p.getPlayertank1(), p.getPlayertankHostId()); // 获取坦克
                        if (tank != null && !tank.canMove()) { // 如果坦克不能移动
                            canTankGo = false; // 设置坦克不能移动
                        }
                    }
                }
            }
        }

        if (!canTankGo || allDie) { // 如果坦克不能移动或所有人都死亡
            return false; // 返回false
        }

        if (playerDir == down) { // 如果方向是向下
            int x = player1.getPlayer1CoorX() + 1; // 下一步X坐标
            int y = player1.getPlayer1CoorY(); // 下一步Y坐标

            String blockname = mapLib.getMapOfName(player1.getMapname()).getPlaceNameOfCoor(x, y); // 获取下一步区域名称
            if (blockname.startsWith("Men")) { // 如果是门
                FCEvent mayBeDoor = eventLib.getEventOfName(mapLib.getMapOfName(player1.getMapname()).getEventNameOfCoor(x, y)); // 获取事件
                if (mayBeDoor instanceof DoorEvent) { // 如果是门事件
                    if (!gameSave.getSaveAllHasUnLockDoors().contains(mayBeDoor.getName())) { // 如果门未解锁
                        return false; // 返回false
                    }
                }
            }

            boolean isExistNPC = FCRMaster.fcv.checkAndGetNpcInXYTag(x + "*" + y) != null; // 检查是否存在NPC
            String key = player1.getMapname() + "*" + x + "*" + y; // 生成键值
            if (isExistNPC) { // 如果存在NPC
                if (gamesave.getBattleBossMaps().containsKey(key) || gamesave.getOtherEventMaps().containsKey(key)) { // 如果是已击败的BOSS或事件
                    isExistNPC = false; // 设置不存在NPC
                }
            }

            boolean isCanPass = true; // 是否可以通过
            if (!gamesave.getOtherEventMaps().containsKey(key)) { // 如果不是其他事件
                if (!hasDriverTankInTeam) // 如果没有驾驶坦克的队友
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 2; // 判断是否可以通过
                else
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 1; // 判断是否可以通过
            }

            if (!isExistNPC && isCanPass) { // 如果不存在NPC且可以通过
                FCRMaster.player1.setPianYiYAndDispatchPianYI(offsetY + vPerStep); // 设置Y轴偏移量
            }
            if (player1.getPianYiY() >= 64 * FCRMaster.fcv.getProportion()) { // 如果Y轴偏移量达到一定值
                player1.movePlayer1Coor(1, 0); // 移动玩家坐标
                FCRMaster.player1.setPianYiYAndDispatchPianYI(0); // 重置Y轴偏移量
                FCRMaster.fcv.setOpenENMonster(true); // 打开怪物
            }
        }

        if (playerDir == up) { // 如果方向是向上
            int x = player1.getPlayer1CoorX() - 1; // 下一步X坐标
            int y = player1.getPlayer1CoorY(); // 下一步Y坐标
            String blockname = mapLib.getMapOfName(player1.getMapname()).getPlaceNameOfCoor(x, y); // 获取下一步区域名称
            if (blockname.startsWith("Men")) { // 如果是门
                FCEvent mayBeDoor = eventLib.getEventOfName(mapLib.getMapOfName(player1.getMapname()).getEventNameOfCoor(x, y)); // 获取事件
                if (mayBeDoor instanceof DoorEvent) { // 如果是门事件
                    if (!gameSave.getSaveAllHasUnLockDoors().contains(mayBeDoor.getName())) { // 如果门未解锁
                        return false; // 返回false
                    }
                }
            }

            String key = player1.getMapname() + "*" + x + "*" + y; // 生成键值
            boolean isExistNPC = FCRMaster.fcv.checkAndGetNpcInXYTag(x + "*" + y) != null; // 检查是否存在NPC
            if (isExistNPC) { // 如果存在NPC
                if (gamesave.getBattleBossMaps().containsKey(key) || gamesave.getOtherEventMaps().containsKey(key)) { // 如果是已击败的BOSS或事件
                    isExistNPC = false; // 设置不存在NPC
                }
            }

            boolean isCanPass = true; // 是否可以通过
            if (!gamesave.getOtherEventMaps().containsKey(key)) { // 如果不是其他事件
                if (!hasDriverTankInTeam) // 如果没有驾驶坦克的队友
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 2; // 判断是否可以通过
                else
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 1; // 判断是否可以通过
            }

            if (!isExistNPC && isCanPass) { // 如果不存在NPC且可以通过
                FCRMaster.player1.setPianYiYAndDispatchPianYI(offsetY - vPerStep); // 设置Y轴偏移量
            }
            if (player1.getPianYiY() <= -(int) (64 * FCRMaster.fcv.getProportion())) { // 如果Y轴偏移量达到一定值
                player1.movePlayer1Coor(-1, 0); // 移动玩家坐标
                FCRMaster.player1.setPianYiYAndDispatchPianYI(0); // 重置Y轴偏移量
                FCRMaster.fcv.setOpenENMonster(true); // 打开怪物
            }
        }

        if (playerDir == left) { // 如果方向是向左
            int x = player1.getPlayer1CoorX(); // 下一步X坐标
            int y = player1.getPlayer1CoorY() - 1; // 下一步Y坐标
            String key = player1.getMapname() + "*" + x + "*" + y; // 生成键值
            boolean isExistNPC = FCRMaster.fcv.checkAndGetNpcInXYTag(x + "*" + y) != null; // 检查是否存在NPC
            if (isExistNPC) { // 如果存在NPC
                if (gamesave.getBattleBossMaps().containsKey(key) || gamesave.getOtherEventMaps().containsKey(key)) { // 如果是已击败的BOSS或事件
                    isExistNPC = false; // 设置不存在NPC
                }
            }

            boolean isCanPass = true; // 是否可以通过
            if (!gamesave.getOtherEventMaps().containsKey(key)) { // 如果不是其他事件
                if (!hasDriverTankInTeam) // 如果没有驾驶坦克的队友
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 2; // 判断是否可以通过
                else
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 1; // 判断是否可以通过
            }

            if (!isExistNPC && isCanPass) { // 如果不存在NPC且可以通过
                FCRMaster.player1.setPianYiXAndDispatchPianYI(offsetX - vPerStep); // 设置X轴偏移量
            }
            if (player1.getPianYiX() <= -(int) (64 * FCRMaster.fcv.getProportion())) { // 如果X轴偏移量达到一定值
                player1.movePlayer1Coor(0, -1); // 移动玩家坐标
                FCRMaster.player1.setPianYiXAndDispatchPianYI(0); // 重置X轴偏移量
                FCRMaster.fcv.setOpenENMonster(true); // 打开怪物
            }
        }

        if (playerDir == right) { // 如果方向是向右
            int x = player1.getPlayer1CoorX(); // 下一步X坐标
            int y = player1.getPlayer1CoorY() + 1; // 下一步Y坐标
            String key = player1.getMapname() + "*" + x + "*" + y; // 生成键值
            boolean isExistNPC = FCRMaster.fcv.checkAndGetNpcInXYTag(x + "*" + y) != null; // 检查是否存在NPC
            if (isExistNPC) { // 如果存在NPC
                if (gamesave.getBattleBossMaps().containsKey(key) || gamesave.getOtherEventMaps().containsKey(key)) { // 如果是已击败的BOSS或事件
                    isExistNPC = false; // 设置不存在NPC
                }
            }

            boolean isCanPass = true; // 是否可以通过
            if (!gamesave.getOtherEventMaps().containsKey(key)) { // 如果不是其他事件
                if (!hasDriverTankInTeam) // 如果没有驾驶坦克的队友
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 2; // 判断是否可以通过
                else
                    isCanPass = mapl.getMapOfName(player1.getMapname()).getMapEntityOfCoor(x, y) < 1; // 判断是否可以通过
            }

            if (!isExistNPC && isCanPass) { // 如果不存在NPC且可以通过
                FCRMaster.player1.setPianYiXAndDispatchPianYI(offsetX + vPerStep); // 设置X轴偏移量
            }
            if (player1.getPianYiX() >= (int) (64 * FCRMaster.fcv.getProportion())) { // 如果X轴偏移量达到一定值
                player1.movePlayer1Coor(0, 1); // 移动玩家坐标
                FCRMaster.player1.setPianYiXAndDispatchPianYI(0); // 重置X轴偏移量
                FCRMaster.fcv.setOpenENMonster(true); // 打开怪物
            }
        }

        if (playerX != player1.getPlayer1x() || playerY != player1.getPlayer1y()) { // 如果坐标发生变化
            gamesave.addStepCount(); // 增加步数
            stepChangeAndCheckLongTermState(); // 检查长期状态
            if (!fcv.isInTeamLink()) { // 如果不在团队链接中
                fcv.closeAllShowWindw(); // 关闭所有显示窗口
            }
        }
        if (offsetX != player1.getPianYiX() || offsetY != player1.getPianYiY() || playerX != player1.getPlayer1x() || playerY != player1.getPlayer1y()) { // 如果有任何变化
            return true; // 返回true
        } else {
            return false; // 返回false
        }
    }

    /**
     * 快速滑行动作，直接向前移动指定方向。
     * 
     * @param dir 移动方向（上、下、左、右）。
     * @return 如果有偏移量或坐标发生变化，则返回 true；否则返回 false。
     */
    public boolean slideAction(int dir){
        int fastSpeed = 80 + player1.getSpeed1() + player1.getSpeed2(); // 计算快速速度
        int vSpeedLevel = 16 - ((fastSpeed - 50) / 20) * 2; // 计算速度等级
        vSpeedLevel = Math.min(vSpeedLevel, 16); // 限制最大速度等级
        vSpeedLevel = Math.max(vSpeedLevel, 6); // 限制最小速度等级
        vSpeedLevel = 4; // 固定速度等级
        int vPerStep = (int) (64 * fcv.getProportion() / vSpeedLevel); // 每步走的像素数
        return moveAction(vPerStep, dir); // 调用移动方法并返回结果
    }
}